目錄
如果將所有 AWS 計算服務劃分為四個大類之一:提供基礎設施即服務(IaaS)、無伺服器、基於容器和平台即服務(PaaS),整理出下表 AWS 雲端計算服務分類表,說明如下:
Amazon EC2 提供虛擬機,可以將其視為基礎設施即服務(IaaS)。它提供了靈活性,但需要用戶承擔更多伺服器管理職責:選擇作業系統、選擇啓動的伺服器大小和資源的功能等。對於具有使用本地計算經驗的IT 專業人員,虛擬機是一個熟悉的概念。Amazon EC2 是最早的AWS 服務之一,目前也仍然是最受歡迎的服務。
AWS Lambda 是一種無需管理的計算平台。通過AWS Lambda,無需預置或管理伺服器即可運行程式碼,只需按使用的計算時間付費即可。這種無伺服器技術概念對於許多IT 專業人員來說尚屬新興技術概念,不過它正在日漸流行,因為它支持原生雲端架構,支持在相同工作負載的情況下,該架構能夠以比7x24 小時運行的伺服器具有更低的成本和實現大規模可擴展性。
基於容器的服務,包括Amazon Elastic Container Service、Amazon Elastic Kubernetes Service、AWS Fargate 和Amazon Elastic Container Registry,能夠在單個作業系統(OS)上運行多個工作負載。與虛擬機相比,容器啓動速度更快,從而可以提供更出色的回應能力,因此,基於容器的解決方案越來越受歡迎。
AWS Elastic Beanstalk 提供了一種平台即服務(PaaS)。通過提供所需的全部應用程式服務,它能幫助您快速建立應用程式。它管理作業系統、應用程式伺服器和其他基礎設施組件,以便用戶可以專注於開發應用程式程式碼。
表 1. AWS雲端計算服務分類表
服務 | 重要概念 | 特性 | 易用性 |
---|---|---|---|
Amazon EC2 | • 基礎設施即服務(IaaS) • 基於個體 • 虛擬機 | 可以根據選擇的配置管理虛擬機 | 許多IT 專業人員熟悉的概念 |
AWS Lambda | • 無伺服器計算• 基於函數• 成本低廉 | • 寫入和部署按計劃執行的程式碼或可以由事件觸發的程式碼• 在需要的情況下使用 | 對於許多IT 員工而言,這是一個相對較新的概念,但在學習用法後很容易使用 |
• Amazon ECS• Amazon EKS• AWS Fargate• Amazon ECR | • 基於容器的計算• 基於實例 | • 更迅速地啓動並執行作業 | AWS Fargate 能夠降低管理開銷,但可以使用為您提供更多控制力的選項 |
• AWS Elastic Beanstalk | • 平台即服務(PaaS)• 適用於Web 應用程式 | • 專注於程式碼• 可以輕鬆綁定到其他服務 | 快速輕鬆地開始使用。 |
AWS Lambda 是一種事件驅動型**無伺服器計算(serverless computing)**服務。Lambda 無需預置或管理伺服器即可運行程式碼。建立一個 Lambda 函數,該函數是包含上傳的程式碼的 AWS 資源。然後,可以將 Lambda 函數的觸發方式設定為按計劃觸發或回應事件觸發。程式碼僅會在被觸發時運行。只需按使用的計算時間付費,程式碼未運行時不產生費用。
不需要瞭解任何新語言、工具或框架即可使用 Lambda。Lambda 支持多種編程語言,包括 Java、Go、PowerShell、Node.js、C#、Python 和 Ruby。程式碼可以使用任意庫,包括本地庫或第三方庫。
Lambda 實現了完全自動化管理。它能管理所有基礎設施,並將程式碼放在高可用性的容錯型基礎設施上運行,能夠專注於構建出色的後端服務。Lambda 可無縫部署程式碼,執行所有的管理、維護和安全補丁操作,並通過 Amazon CloudWatch 提供內置日誌記錄和監控。
Lambda 提供內置容錯能力。它可在各區域中跨多個可用區維護計算容量,從而幫助保護程式碼免受單個機器故障或資料中心故障的影響。沒有維護時段或計劃停機時間。可以通過使用 AWS Step Functions 構建工作流來編排多個 AWS Lambda 函數,用於複雜或長時間運行的任務。請使用Step Functions 來定義工作流。這些工作流使用順序、並行、分支和錯誤處理步驟觸發 Lambda 函數集合。藉助 Step Functions 和 Lambda,可以為應用程式和後端構建有狀態、長時間運行的行程。
使用 Lambda,只需為提供的請求以及運行程式碼所需的計算時間付費。帳單以 100 毫秒的增量計費,從而能經濟高效且輕鬆地從每天幾個請求自動擴展到每秒數千個請求。
事件源是 AWS 服務或開發人員建立的應用程式,用於生成可觸發 AWS Lambda 函數使其運行的事件。某些服務通過直接呼叫 Lambda 函數將事件發佈到Lambda。這些異步呼叫 Lambda 函數的服務包括但不限於 Amazon S3、Amazon Simple Notification Service(Amazon SNS) 和 Amazon CloudWatch Events。
Lambda 也可以在未向 Lambda 發佈事件的其他服務中輪詢資源。例如,Lambda 可以從 Amazon Simple Queue Service(Amazon SQS)佇列中輪詢記錄,然後針對獲得的每條消息執行 Lambda 函數。類似地,Lambda 也可以從 Amazon DynamoDB 讀取事件。某些服務可以直接呼叫 Lambda 函數,例如 Elastic Load Balancing(Application Load Balancer(應用程式負載均衡器))和 Amazon API Gateway。
直接使用 Lambda 控制台、Lambda API、AWS 軟體開發工具包(SDK)、AWS CLI 和 AWS 工具箱來呼叫 Lambda 函數。直接呼叫有時很有用,例如在開發移動應用程式並希望該應用程式呼叫 Lambda 函數時。
AWS Lambda 會使用 Amazon CloudWatch 自動監控 Lambda 函數。為了排除函數中的故障,Lambda 日誌記錄了函數處理的所有請求。它還會自動儲存由程式碼通過 Amazon CloudWatch Logs 生成的日誌。
使用 AWS 管理控制台建立 Lambda 函數時,請首先給函數命名。然後,可以指定:
圖 1. Lambda 控制台
以上所有設定最終都儲存在 Lambda 部署程式包(一個包含函數程式碼和相依函式庫的ZIP 歸檔)中。使用 Lambda 控制台編寫函數時,控制台會管理軟體包。但是,如果使用 Lambda API 來管理函數,則需要建立部署程式包。
現在,請設想一個基於事件的 Lambda 函數的示例使用案例。假設您要為將上傳到 S3 儲存桶的每個圖像(.jpg 或 .png 物件)建立縮略圖。為了構建解決方案,您可以建立 Lambda 函數,在上傳物件後,Amazon S3 可以呼叫該函數。之後,Lambda 函數從源儲存桶讀取圖像物件並在目標儲存桶中建立縮略圖。下面是它的工作流程:
❶用戶將圖片上傳到 Amazon S3 中的來源儲存桶(物件建立事件)。
❷Amazon S3 檢測到物件建立事件。
❸Amazon S3 通過呼叫 Lambda 函數和傳遞事件資料,將圖片建立的事件發佈到 Lambda。
❹Lambda 通過代入建立 Lambda 函數時指定的執行角色來執行 Lambda 函數。
❺Lambda 函數通過收到的事件資料獲得了來源儲存桶名稱和物件鍵名稱(圖片名稱)。Lambda 函數讀取該圖片,使用圖形庫建立縮圖,然後將縮圖保存到目標儲存桶。
圖 2. 基於事件的 Lambda 函數建立縮圖範例
在建立和部署 Lambda 函數時,AWS Lambda 具有一些已知的限制。AWS Lambda 會限制可用於運行和儲存函數的計算和儲存資源量。例如,單個 Lambda 函數的最大記憶體分配容量為 3008 MB;在一個區域中,函數只能有 1000 個並行執行;AWS Lambda 函數可以配置為每次執行最長運行 15 分鐘。可以將超時設定為 1 秒到 15 分鐘之間的任何值;函數的部署程式包的大小不能超過 250MB。
層是包含庫、自定義運行時或其他相依函式庫的ZIP 歸檔。利用層可以在函數中使用庫,而不必將庫包含在部署程式包中。使用層有助於避免達到部署程式包的大小限制,層還適用於在 Lambda 函數之間共享程式碼和資料。
限制分為軟性限制和硬性限制,帳戶的軟性限制可以通過提交支持通知單並為提供請求理由來申請放寬。硬性限制不能放寬。
部署 Lambda Function 的方法有底下這些方式,可以看出 AWS Lambda 其實是 AWS 的一項核心功能
不管是上面哪一種作法,實際上 AWS Lambda 實際的運行方式就是以容器(Container)的方式在執行。
在 AWS Lambda 的開發中,可以分成下列幾個步驟:
以下簡單說明一下如何利用 AWS 管理主控台開發 Lambda Function
要建立 Lambda 函數並且調用它看到最後的結果,要確保開發者的 IAM 使用者擁有建立並調用 Lambda 函數和查看日誌的權限。
該 IAM 權限策略只能確保用戶查看當前帳戶的所有權限策略,而不能做出增加或者刪除等操作。
IAM 策略如下:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": [
"iam:CreateRole",
"iam:ListPolicies",
"iam:GetPolicyVersion",
"iam:PassRole",
"iam:ListAttachedUserPolicies",
"iam:CreatePolicy",
"iam:AttachRolePolicy",
"iam:ListUsers",
"iam:ListUserPolicies"
],
"Resource": "*"
}
]
}
用戶擁有 CloudWatch Logs 之後,AWS 才允許用戶查看 Lambda 函數的運行日誌,方便用戶 debug 。
CloudWatch Logs 策略如下:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": [
"logs:DescribeLogGroups",
"logs:DescribeLogStreams",
"logs:GetLogEvents"
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "arn:aws:logs:*:*:*"
}
]
}
建立 Lambda 函數並且調用函數的權限,這就需要帳戶擁有相關 Lambda 的權限。
Lambda 策略如下:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": [
"lambda:CreateFunction",
"lambda:UpdateFunctionCode",
"lambda:ListFunctions",
"lambda:InvokeFunction",
"lambda:GetFunction",
"lambda:GetAccountSettings"
],
"Resource": "*"
}
]
}
信任策略會向 Lambda 服務授予代入角色並代表用戶呼叫 Lambda 函數的權限。
Trust policy 如下:
{
"Effect": "Allow",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
需要配置函數資料如下:
在 Lambda 函數中撰寫要運行的程式碼,在程式碼頁簽中程式碼來源撰寫測試的程式。
import json
def lambda_handler(event, context):
layer = int(event.get('layer_nums'))
for i in range(layer):
print('*'*(layer - i), (i+1))
print('total layers: {}!'.format(str(layer)))
return {
'statusCode': 200,
'body':json.dumps('Hello from Lambda! from webconsole!')
}
圖 3. 編寫程式碼
編寫完成程式碼之後,由於還沒有部署,無法進行測試或者調用。部署類似於將程式碼同步到 Lambda 函數中,部署程式碼,點擊 Deploy,撰寫完程式碼之後需要部署程式碼,之後才能進行測試。
編寫完成程式碼並且部署成功之後,可以進行測試 / 調用 Lambda 函數,得到結果。
點擊Test
設定測試事件
{
"layer_nums": "8"
}
點擊儲存,完成設定
用戶在調用 Lambda 函數之後,可以查看其對應的 CloudWatch Logs 日誌,來 Lambda 函數程式碼中的錯誤或者需要修改的地方。簡單來說就是方便用戶 debug。
調用 Lambda 函數之後點擊監控頁簽,點擊查看 CloudWatch Logs
圖 6. 打開 CloudWatch Logs
在日誌流頁簽找到對應調用時間的日誌流。
圖 7. 找到對應調用函數的日誌流
在日志事件中查看 Lambda 函數的調用結果
圖 8. 查看 Lambda 函數調用結果
當程式碼細節需要修改或者需求發生更改等情況發生的時候,就需要更新編寫的 Lambda 程式碼。在本節將講述如何使用 AWS 管理主控台更新 Lambda 程式碼。
*
改成 @
import json
def lambda_handler(event, context):
layer = int(event.get('layer_nums'))
for i in range(layer):
print('@'*(layer - i), (i+1))
print('total layers: {}!'.format(str(layer)))
return {
'statusCode': 200,
'body':json.dumps('Hello from Lambda! from webconsole!')
}